package nayasis.common.db.manager.sql.condition;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import nayasis.common.db.manager.sql.condition.node.BraceNode;
import nayasis.common.db.manager.sql.condition.node.ConstantNode;
import nayasis.common.db.manager.sql.condition.node.Node;
import nayasis.common.db.manager.sql.type.Brace;
import nayasis.common.db.manager.sql.type.Type;
import nayasis.common.exception.unchecked.SyntaxException;

public class BraceParser {

    public List<Expression> tokenizeBrace( List<Node> nodes ) {
        
        List<Expression> result = new ArrayList<>();
        
        List<Node> item = new ArrayList<>();
        
        Stack<Integer> stackBrace = new Stack<>();
        
        for( int i = 0, iCnt = nodes.size(); i < iCnt; i++ ) {
            
            Node node = nodes.get( i );
            
            if( ! node.is(Type.brace) ) continue;

            BraceNode braceNode = (BraceNode) node;

            switch( braceNode.get() ) {
                case open  :
                    
                    if( stackBrace.size() == 0 && i > 0 ) {
                        item = new ArrayList<>();
                    }
                    
                    break;
                case close :
                    break;
                    
            }
            
        }
        
        return result;
        
    }

    private void setSingleNodeInNodes( List<Node> nodes ) {

        Stack<Integer> braceChecker = new Stack<>();
        
        for( int i = 0, iCnt = nodes.size(); i < iCnt; i++ ) {
            
            Node node = nodes.get( i );
            
            if( ! node.is(Type.brace) ) continue;

            BraceNode braceNode = (BraceNode) node;

            switch( braceNode.get() ) {
                
                case open  :
                    braceChecker.add( i );
                    break;

                case close :
                    
                    int openIndex = braceChecker.pop();
                    
                    if( i - openIndex == 2 )  {
                        nodes.remove( i );
                        nodes.remove( openIndex);
                    } else if( i - openIndex == 1 ) {
                        nodes.remove( i );
                        nodes.remove( openIndex);
                        nodes.add( i, new ConstantNode( null ) );
                        
                    }
                    break;
                    
            }
            
        }
        
    }
    
    public List<Expression> parse( String context ) {
        
        StringBuffer string = new StringBuffer( context );
        
        if( ! hasBrace(string) ) {
            return null;
        }
        
        List<Expression> expressionList = new ArrayList<Expression>();

        Stack<Integer> stackBrace = new Stack<>();
        
        int searchStartIndex = 0;
        
        for( int i = 0, iCnt = string.length(); i < iCnt; i++ ) {
            
            char c = string.charAt( i );
            
            if( isStartBrace( c ) ) {
                
                if( stackBrace.size() == 0 && i > 0 ) {

                    String newContext = string.substring( searchStartIndex, i );
                    
                    expressionList.add( new Expression(newContext) );
                    
                }
                
                stackBrace.push( i );
                continue;
            }

            if( isEndBrace( c ) ) {
                
                int startIndex = stackBrace.pop();
                
                if( stackBrace.size() > 0 ) continue;
                
                if( i - startIndex == 1 ) continue;
                
                String newContext = string.substring( startIndex + 1, i );
                
                expressionList.add( new Expression(newContext) );
                
                searchStartIndex = i + 1;
                
            }
            
        }

        checkMissingBrace( string, stackBrace );
        
        if( searchStartIndex < string.length() ) {
            
            String newContext = string.substring( searchStartIndex, string.length() );

            expressionList.add( new Expression(newContext) );
            
        }
        
        return expressionList;
        
    }

    private void checkMissingBrace( StringBuffer sb, Stack<Integer> stackBrace ) {

        if( stackBrace.size() > 0 ) {
            throw new SyntaxException( "There is unclosed brace (@)", sb.toString() );
        }

    }

    private boolean hasBrace( StringBuffer string ) {
        
        for( int i = 0, iCnt = string.length(); i < iCnt; i++ ) {
            
            char c = string.charAt( i );
            
            if( isStartBrace(c) ) return true;
            
        }
    
        return false;
        
    }
    
    private boolean isEndBrace( char c ) {
        return c == ')' || c == ']' || c == '}';
    }

    private boolean isStartBrace( char c ) {
        return c == '(' || c == '[' || c == '{';
    }
    
}
